package com.ruoyi.generator.util

import com.alibaba.fastjson2.JSON
import com.alibaba.fastjson2.JSONObject
import com.ruoyi.common.constant.GenConstants
import com.ruoyi.common.utils.DateUtils.date
import com.ruoyi.common.utils.MyStringUtils
import com.ruoyi.generator.domain.GenTable
import com.ruoyi.generator.domain.GenTableColumn
import org.apache.velocity.VelocityContext

/**
 * 模板处理工具类
 *
 * @author ruoyi
 */
object VelocityUtils {
    /** 项目空间路径  */
    private const val PROJECT_PATH = "main/kotlin"

    /** mybatis空间路径  */
    private const val MYBATIS_PATH = "main/resources/mapper"

    /** 默认上级菜单，系统工具  */
    private const val DEFAULT_PARENT_MENU_ID = "3"

    /**
     * 设置模板变量信息
     *
     * @return 模板列表
     */
    fun prepareContext(genTable: GenTable?): VelocityContext {
        val moduleName = genTable?.moduleName
        val businessName = genTable?.businessName
        val packageName = genTable?.packageName
        val tplCategory = genTable?.tplCategory
        val functionName = genTable?.functionName
        val velocityContext = VelocityContext()
        velocityContext.put("tplCategory", genTable?.tplCategory)
        velocityContext.put("tableName", genTable?.tableName)
        velocityContext.put("functionName", if (MyStringUtils.isNotEmpty(functionName!!)) functionName else "【请填写功能名称】")
        velocityContext.put("ClassName", genTable.className)
        velocityContext.put("className", org.apache.commons.lang3.StringUtils.uncapitalize(genTable.className))
        velocityContext.put("moduleName", genTable.moduleName)
        velocityContext.put("BusinessName", org.apache.commons.lang3.StringUtils.capitalize(genTable.businessName))
        velocityContext.put("businessName", genTable.businessName)
        velocityContext.put("basePackage", getPackagePrefix(packageName))
        velocityContext.put("packageName", packageName)
        velocityContext.put("author", genTable.functionAuthor)
        velocityContext.put("datetime", date)
        velocityContext.put("pkColumn", genTable.pkColumn)
        velocityContext.put("importList", getImportList(genTable))
        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName))
        velocityContext.put("columns", genTable.columns)
        velocityContext.put("table", genTable)
        velocityContext.put("dicts", getDicts(genTable))
        setMenuVelocityContext(velocityContext, genTable)
        if (GenConstants.TPL_TREE == tplCategory) {
            setTreeVelocityContext(velocityContext, genTable)
        }
        if (GenConstants.TPL_SUB == tplCategory) {
            setSubVelocityContext(velocityContext, genTable)
        }
        return velocityContext
    }

    fun setMenuVelocityContext(context: VelocityContext, genTable: GenTable) {
        val options = genTable.options
        val paramsObj = JSON.parseObject(options)
        val parentMenuId = getParentMenuId(paramsObj)
        context.put("parentMenuId", parentMenuId)
    }

    fun setTreeVelocityContext(context: VelocityContext, genTable: GenTable) {
        val options = genTable.options
        val paramsObj = JSON.parseObject(options)
        val treeCode = getTreecode(paramsObj)
        val treeParentCode = getTreeParentCode(paramsObj)
        val treeName = getTreeName(paramsObj)
        context.put("treeCode", treeCode)
        context.put("treeParentCode", treeParentCode)
        context.put("treeName", treeName)
        context.put("expandColumn", getExpandColumn(genTable))
        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
            context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE))
        }
        if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
            context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME))
        }
    }

    fun setSubVelocityContext(context: VelocityContext, genTable: GenTable) {
        val subTable = genTable.subTable
        val subTableName = genTable.subTableName
        val subTableFkName = genTable.subTableFkName
        val subClassName = genTable.subTable!!.className
        val subTableFkClassName = MyStringUtils.convertToCamelCase(subTableFkName)
        context.put("subTable", subTable)
        context.put("subTableName", subTableName)
        context.put("subTableFkName", subTableFkName)
        context.put("subTableFkClassName", subTableFkClassName)
        context.put("subTableFkclassName", org.apache.commons.lang3.StringUtils.uncapitalize(subTableFkClassName))
        context.put("subClassName", subClassName)
        context.put("subclassName", org.apache.commons.lang3.StringUtils.uncapitalize(subClassName))
        context.put("subImportList", getImportList(genTable.subTable))
    }

    /**
     * 获取模板信息
     * @param tplCategory 生成的模板
     * @param tplWebType 前端类型
     * @return 模板列表
     */
    fun getTemplateList(tplCategory: String?, tplWebType: String?): List<String> {
        var useWebType = "vm/vue"
        if ("element-plus" == tplWebType) {
            useWebType = "vm/vue/v3"
        }
        val templates: MutableList<String> = mutableListOf()
        templates.add("vm/kotlin/domain.kt.vm")
        templates.add("vm/kotlin/mapper.kt.vm")
        templates.add("vm/kotlin/service.kt.vm")
        templates.add("vm/kotlin/serviceImpl.kt.vm")
        templates.add("vm/kotlin/controller.kt.vm")
        templates.add("vm/xml/mapper.xml.vm")
        templates.add("vm/sql/sql.vm")
        templates.add("vm/js/api.js.vm")
        if (GenConstants.TPL_CRUD == tplCategory) {
            templates.add("$useWebType/index.vue.vm")
        } else if (GenConstants.TPL_TREE == tplCategory) {
            templates.add("$useWebType/index-tree.vue.vm")
        } else if (GenConstants.TPL_SUB == tplCategory) {
            templates.add("$useWebType/index.vue.vm")
            templates.add("vm/kotlin/sub-domain.kt.vm")
        }
        return templates
    }

    /**
     * 获取文件名
     */
    fun getFileName(template: String, genTable: GenTable?): String {
        // 文件名称
        var fileName = ""
        // 包路径
        val packageName = genTable?.packageName
        // 模块名
        val moduleName = genTable?.moduleName
        // 大写类名
        val className = genTable?.className
        // 业务名称
        val businessName = genTable?.businessName
        val javaPath = PROJECT_PATH + "/" + org.apache.commons.lang3.StringUtils.replace(packageName, ".", "/")
        val mybatisPath = "$MYBATIS_PATH/$moduleName"
        val vuePath = "vue"
        if (template.contains("domain.kt.vm")) {
            fileName = MyStringUtils.format("{}/domain/{}.kt", javaPath, className)
        }
        if (template.contains("sub-domain.kt.vm") && GenConstants.TPL_SUB==genTable?.tplCategory) {
            fileName = MyStringUtils.format("{}/domain/{}.kt", javaPath, genTable.subTable?.className)
        } else if (template.contains("mapper.kt.vm")) {
            fileName = MyStringUtils.format("{}/mapper/{}Mapper.kt", javaPath, className)
        } else if (template.contains("service.kt.vm")) {
            fileName = MyStringUtils.format("{}/service/I{}Service.kt", javaPath, className)
        } else if (template.contains("serviceImpl.kt.vm")) {
            fileName = MyStringUtils.format("{}/service/impl/{}ServiceImpl.kt", javaPath, className)
        } else if (template.contains("controller.kt.vm")) {
            fileName = MyStringUtils.format("{}/controller/{}Controller.kt", javaPath, className)
        } else if (template.contains("mapper.xml.vm")) {
            fileName = MyStringUtils.format("{}/{}Mapper.xml", mybatisPath, className)
        } else if (template.contains("sql.vm")) {
            fileName = businessName + "Menu.sql"
        } else if (template.contains("api.js.vm")) {
            fileName = MyStringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName)
        } else if (template.contains("index.vue.vm")) {
            fileName = MyStringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName)
        } else if (template.contains("index-tree.vue.vm")) {
            fileName = MyStringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName)
        }
        return fileName
    }

    /**
     * 获取包前缀
     *
     * @param packageName 包名称
     * @return 包前缀名称
     */
    fun getPackagePrefix(packageName: String?): String {
        val lastIndex = packageName!!.lastIndexOf(".")
        return MyStringUtils.mySubstring(packageName, 0, lastIndex)
    }

    /**
     * 根据列类型获取导入包
     *
     * @param genTable 业务表对象
     * @return 返回需要导入的包列表
     */
    fun getImportList(genTable: GenTable?): HashSet<String> {
        val columns: List<GenTableColumn>? = genTable!!.columns
        val subGenTable = genTable.subTable
        val importList = HashSet<String>()
        if (MyStringUtils.isNotNull(subGenTable)) {
            importList.add("java.util.List")
        }
        for (column in columns!!) {
            if (!column.isSuperColumn && GenConstants.TYPE_DATE == column.javaType) {
                importList.add("java.util.Date")
                importList.add("com.fasterxml.jackson.annotation.JsonFormat")
            } else if (!column.isSuperColumn && GenConstants.TYPE_BIGDECIMAL == column.javaType) {
                importList.add("java.math.BigDecimal")
            }
        }
        return importList
    }

    /**
     * 根据列类型获取字典组
     *
     * @param genTable 业务表对象
     * @return 返回字典组
     */
    fun getDicts(genTable: GenTable): String {
        val columns: List<GenTableColumn>? = genTable.columns
        val dicts: MutableSet<String> = mutableSetOf()
        addDicts(dicts, columns)
        if (MyStringUtils.isNotNull(genTable.subTable)) {
            val subColumns: List<GenTableColumn>? = genTable.subTable!!.columns
            addDicts(dicts, subColumns)
        }
        return org.apache.commons.lang3.StringUtils.join(dicts, ", ")
    }

    /**
     * 添加字典列表
     *
     * @param dicts 字典列表
     * @param columns 列集合
     */
    fun addDicts(dicts: MutableSet<String>, columns: List<GenTableColumn>?) {
        for (column in columns!!) {
            if (!column.isSuperColumn && MyStringUtils.isNotEmpty(column.dictType!!) && org.apache.commons.lang3.StringUtils.equalsAny(
                            column.htmlType,
                            *arrayOf(GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX))) {
                dicts.add("'" + column.dictType + "'")
            }
        }
    }

    /**
     * 获取权限前缀
     *
     * @param moduleName 模块名称
     * @param businessName 业务名称
     * @return 返回权限前缀
     */
    fun getPermissionPrefix(moduleName: String?, businessName: String?): String {
        return MyStringUtils.format("{}:{}", moduleName, businessName)
    }

    /**
     * 获取上级菜单ID字段
     *
     * @param paramsObj 生成其他选项
     * @return 上级菜单ID字段
     */
    fun getParentMenuId(paramsObj: JSONObject): String {
        return if (MyStringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
                && MyStringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID))) {
            paramsObj.getString(GenConstants.PARENT_MENU_ID)
        } else DEFAULT_PARENT_MENU_ID
    }

    /**
     * 获取树编码
     *
     * @param paramsObj 生成其他选项
     * @return 树编码
     */
    fun getTreecode(paramsObj: JSONObject): String? {
        return if (paramsObj.containsKey(GenConstants.TREE_CODE)) {
            MyStringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE))
        } else org.apache.commons.lang3.StringUtils.EMPTY
    }

    /**
     * 获取树父编码
     *
     * @param paramsObj 生成其他选项
     * @return 树父编码
     */
    fun getTreeParentCode(paramsObj: JSONObject): String? {
        return if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
            MyStringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE))
        } else org.apache.commons.lang3.StringUtils.EMPTY
    }

    /**
     * 获取树名称
     *
     * @param paramsObj 生成其他选项
     * @return 树名称
     */
    fun getTreeName(paramsObj: JSONObject): String? {
        return if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
            MyStringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME))
        } else org.apache.commons.lang3.StringUtils.EMPTY
    }

    /**
     * 获取需要在哪一列上面显示展开按钮
     *
     * @param genTable 业务表对象
     * @return 展开按钮列序号
     */
    fun getExpandColumn(genTable: GenTable): Int {
        val options = genTable.options
        val paramsObj = JSON.parseObject(options)
        val treeName = paramsObj.getString(GenConstants.TREE_NAME)
        var num = 0
        for (column in genTable.columns!!) {
            if (column.isList()) {
                num++
                val columnName = column.columnName
                if (columnName == treeName) {
                    break
                }
            }
        }
        return num
    }
}
